package fieldmaps.memory;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Polygon;

import fieldmaps.database.GenericMap;

public class MemoryGenericMap implements GenericMap {
//	private static Logger LOGGER = Logger.getLogger(MemoryGenericMap.class);
	
	private GeometryFactory factory;
	private List<Polygon> cells;
	private Envelope limits;
	private Integer index;
	
	public MemoryGenericMap() {
		factory = new GeometryFactory();
		cells = new LinkedList<Polygon>();
	}

	@Override
	public void addCell(Coordinate[] coordinates, int value) throws SQLException {
		LinearRing ring = factory.createLinearRing(coordinates);
		Polygon polygon = new Polygon(ring, null, factory);
		polygon.setUserData(value);
		cells.add(polygon);
	}

	@Override
	public List<Polygon> getAllCells() throws SQLException {
		return cells;
	}

	@Override
	public List<Polygon> getCell(Coordinate coordinate) {
		List<Polygon> resp = new ArrayList<Polygon>();
		for (Polygon polygon : cells) {
			if (polygon.contains(factory.createPoint(coordinate))) {
				resp.add(polygon);
			}
		}
		return resp;
	}

	@Override
	public List<Polygon> getCellNeighbors(Polygon cell) {
		List<Polygon> resp = new ArrayList<Polygon>();
		for (Polygon polygon : cells) {
			if (polygon.touches(cell)) {
				resp.add(polygon);
			}
		}
		return resp;
	}

	@Override
	public List<Polygon> getPolygonsIntersection(Polygon cell) {
		List<Polygon> resp = new ArrayList<Polygon>();
		for (Polygon polygon : cells) {
			if (polygon.intersects(polygon)) {
				resp.add(polygon);
			}
		}
		return resp;
	}

	@Override
	public void getPolygonsIntersecArea(Polygon polygon, List<Polygon> outputPolygonsIntersection, List<Double> outputPolygonsAreas) {
		if (outputPolygonsAreas == null || outputPolygonsIntersection == null || polygon == null || !outputPolygonsAreas.isEmpty()
				|| !outputPolygonsIntersection.isEmpty()) {
			throw new IllegalArgumentException();
		}
		Double area;
		for (Polygon cell: cells) {
			area = cell.intersection(polygon).getArea();
			if (area != 0.0) {
				outputPolygonsIntersection.add(cell);
				outputPolygonsAreas.add(area);
			}
		}
	}

	@Override
	public Coordinate[] getBorderCoordinates() {
		Coordinate[] coordinates = new Coordinate[2];
		coordinates[0] = new Coordinate(limits.getMaxY(), limits.getMinX());
		coordinates[1] = new Coordinate(limits.getMaxX(), limits.getMinY());
		return coordinates;
	}

	@Override
	public Double getMapArea() {
		return limits.getArea();
	}

	@Override
	public void startCellIteration() {
		index = 0;
	}

	@Override
	public void resetCellIteration() {
		index = 0;
	}

	@Override
	public Polygon getNextCell() throws NoSuchElementException {
		Polygon polygon = cells.get(index);
		index++;
		return polygon;
	}

	@Override
	public Map<Object, Double> getWeightedNeighborsArea(Polygon polygon)
			throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

//	@Override
//	public GenericMap binaryOperation(GenericMap otherMap, ICallbackBinary callback) throws MapAlgebraException {
//		return null;
//	}
//
//	@Override
//	public GenericMap unaryOperation(ICallbackUnary callback) throws MapAlgebraException {
//		try {
//			GenericMap newMap = new MemoryGenericMap();
//			for (Polygon cell: cells) {
//				newMap.addCell(cell.getCoordinates(), (Integer)callback.doOperation(cell.getUserData()));
//			}
//			return newMap;
//		} catch (SQLException e) {
//			LOGGER.error(e.getMessage());
//			return null;
//		}
//	}

}
